﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using EuroManager.Domain.Simulator.Engine;
using EuroManager.Domain.Simulator.Helpers;

namespace EuroManager.Domain.Simulator.World
{
    [ContractClass(typeof(BallContract))]
    public interface IBall : IMovingEntity
    {
        bool HasOwner { get; }
        
        IPlayer Owner { get; }
        
        ITeam OwningTeam { get; }
        
        IEnumerable<TimeLocation> FutureLocations { get; }
        
        void Trap(IPlayer player);
        
        void Free();
        
        void Kick(Vector2D velocity);

        void KickAt(Vector2D target, float speedAtTarget);
    }

    [ContractClassFor(typeof(IBall))]
    public abstract class BallContract : IBall
    {
        public abstract bool HasOwner { get; }

        public abstract IPlayer Owner { get; }

        public abstract ITeam OwningTeam { get; }

        public abstract IEnumerable<TimeLocation> FutureLocations { get; }

        public abstract Vector2D Location { get; }

        public abstract float X { get; }

        public abstract float Y { get; }

        public abstract Vector2D Velocity { get; }

        public abstract Vector2D Heading { get; }

        public abstract bool IsMoving { get; }

        public abstract float Speed { get; }
        
        public void Trap(IPlayer player)
        {
            Contract.Requires(player != null);
        }

        public abstract void Free();

        public void Kick(Vector2D velocity)
        {
            Contract.Requires(!velocity.IsZero);
        }

        public void KickAt(Vector2D target, float speedAtTarget)
        {
            Contract.Requires(speedAtTarget.IsRational() && speedAtTarget >= 0);
        }
        
        public abstract float DistanceTo(Vector2D target);

        public abstract float DistanceTo(IMovingEntity entity);

        public abstract Vector2D DirectionTo(Vector2D target);

        public abstract Vector2D DirectionTo(IMovingEntity entity);

        public abstract void Turn(Vector2D target);
        
        public abstract void Update(float elapsedTime);
    }
}
